use axum::{
    extract::{DefaultBodyLimit, Query},
    routing::{get, post},
    Router,
};
use serde::Deserialize;

use crate::{
    error::AppErr,
    server::{
        res::{new_download, DownloadFile, Void},
        Cbor,
    },
    store::firm::{self, TbFirm},
};

#[derive(Debug, Deserialize)]
struct CreateReq {
    firm_type: u8,
    version: String,
    description: String,
    name: String,
    #[serde(with = "serde_bytes")]
    body: Box<[u8]>,
}

async fn on_create(req: Cbor<CreateReq>) -> Result<Cbor<u64>, AppErr> {
    let id = firm::create(
        req.firm_type,
        &req.version,
        &req.description,
        &req.name,
        &req.body,
    )
    .await?;
    Ok(Cbor(id))
}

#[derive(Debug, Deserialize)]
struct QueryReq {
    firm_type: u8,
}

async fn on_query(req: Query<QueryReq>) -> Result<Cbor<Box<[TbFirm]>>, AppErr> {
    let res = firm::query_all(req.firm_type).await?;
    Ok(Cbor(res))
}

#[derive(Debug, Deserialize)]
struct DeleteReq {
    id: u64,
}

async fn on_delete(req: Cbor<DeleteReq>) -> Result<Void, AppErr> {
    firm::delete(req.id).await?;
    Ok(Void)
}

#[derive(Debug, Deserialize)]
struct DownloadReq {
    id: u64,
}

async fn on_download(req: Query<DownloadReq>) -> Result<DownloadFile, AppErr> {
    let ff = firm::download(req.id).await?;
    Ok(new_download(ff.name, ff.body))
}

const MAX_PKG_SIZE: usize = 10 * 1024 * 1024;

pub fn register() -> Router {
    Router::new()
        .route("/create", post(on_create))
        .layer(DefaultBodyLimit::max(MAX_PKG_SIZE))
        .route("/query_all", get(on_query))
        .route("/delete", post(on_delete))
        .route("/download", get(on_download))
}
